home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / awksrc.zip / AWK.Y < prev    next >
Text File  |  1993-09-28  |  42KB  |  1,794 lines

  1. /*
  2.  * awk.y --- yacc/bison parser
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. %{
  27. #ifdef DEBUG
  28. #define YYDEBUG 12
  29. #endif
  30.  
  31. #define    YYMAXDEPTH    300
  32. #define    YYSSIZE    YYMAXDEPTH
  33.  
  34. #include "awk.h"
  35.  
  36. static void yyerror (); /* va_alist */
  37. static char *get_src_buf P((void));
  38. static int yylex P((void));
  39. static NODE *node_common P((NODETYPE op));
  40. static NODE *snode P((NODE *subn, NODETYPE op, int sindex));
  41. static NODE *mkrangenode P((NODE *cpair));
  42. static NODE *make_for_loop P((NODE *init, NODE *cond, NODE *incr));
  43. static NODE *append_right P((NODE *list, NODE *new));
  44. static void func_install P((NODE *params, NODE *def));
  45. static void pop_var P((NODE *np, int freeit));
  46. static void pop_params P((NODE *params));
  47. static NODE *make_param P((char *name));
  48. static NODE *mk_rexp P((NODE *exp));
  49.  
  50. static int want_assign;        /* lexical scanning kludge */
  51. static int want_regexp;        /* lexical scanning kludge */
  52. static int can_return;        /* lexical scanning kludge */
  53. static int io_allowed = 1;    /* lexical scanning kludge */
  54. static char *lexptr;        /* pointer to next char during parsing */
  55. static char *lexend;
  56. static char *lexptr_begin;    /* keep track of where we were for error msgs */
  57. static char *lexeme;        /* beginning of lexeme for debugging */
  58. static char *thisline = NULL;
  59. #define YYDEBUG_LEXER_TEXT (lexeme)
  60. static int param_counter;
  61. static char *tokstart = NULL;
  62. static char *token = NULL;
  63. static char *tokend;
  64.  
  65. NODE *variables[HASHSIZE];
  66.  
  67. extern char *source;
  68. extern int sourceline;
  69. extern char *cmdline_src;
  70. extern char **srcfiles;
  71. extern int errcount;
  72. extern NODE *begin_block;
  73. extern NODE *end_block;
  74. %}
  75.  
  76. %union {
  77.     long lval;
  78.     AWKNUM fval;
  79.     NODE *nodeval;
  80.     NODETYPE nodetypeval;
  81.     char *sval;
  82.     NODE *(*ptrval)();
  83. }
  84.  
  85. %type <nodeval> function_prologue function_body
  86. %type <nodeval> rexp exp start program rule simp_exp
  87. %type <nodeval> non_post_simp_exp post_inc_dec_exp
  88. %type <nodeval> pattern 
  89. %type <nodeval>    action variable param_list
  90. %type <nodeval>    rexpression_list opt_rexpression_list
  91. %type <nodeval>    expression_list opt_expression_list
  92. %type <nodeval>    statements statement if_statement opt_param_list 
  93. %type <nodeval> opt_exp opt_variable regexp 
  94. %type <nodeval> input_redir output_redir
  95. %type <nodetypeval> print
  96. %type <sval> func_name
  97. %type <lval> lex_builtin
  98.  
  99. %token <sval> FUNC_CALL NAME REGEXP
  100. %token <lval> ERROR
  101. %token <nodeval> YNUMBER YSTRING
  102. %token <nodetypeval> RELOP APPEND_OP
  103. %token <nodetypeval> ASSIGNOP MATCHOP NEWLINE CONCAT_OP
  104. %token <nodetypeval> LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
  105. %token <nodetypeval> LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
  106. %token <nodetypeval> LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
  107. %token <nodetypeval> LEX_GETLINE
  108. %token <nodetypeval> LEX_IN
  109. %token <lval> LEX_AND LEX_OR INCREMENT DECREMENT
  110. %token <lval> LEX_BUILTIN LEX_LENGTH
  111.  
  112. /* these are just yylval numbers */
  113.  
  114. /* Lowest to highest */
  115. %right ASSIGNOP
  116. %right '?' ':'
  117. %left LEX_OR
  118. %left LEX_AND
  119. %left LEX_GETLINE
  120. %nonassoc LEX_IN
  121. %left FUNC_CALL LEX_BUILTIN LEX_LENGTH
  122. %nonassoc MATCHOP
  123. %nonassoc RELOP '<' '>' '|' APPEND_OP
  124. %left CONCAT_OP
  125. %left YSTRING YNUMBER
  126. %left '+' '-'
  127. %left '*' '/' '%'
  128. %right '!' UNARY
  129. %right '^'
  130. %left INCREMENT DECREMENT
  131. %left '$'
  132. %left '(' ')'
  133. %%
  134.  
  135. start
  136.     : opt_nls program opt_nls
  137.         { expression_value = $2; }
  138.     ;
  139.  
  140. program
  141.     : rule
  142.         { 
  143.             if ($1 != NULL)
  144.                 $$ = $1;
  145.             else
  146.                 $$ = NULL;
  147.             yyerrok;
  148.         }
  149.     | program rule
  150.         /* add the rule to the tail of list */
  151.         {
  152.             if ($2 == NULL)
  153.                 $$ = $1;
  154.             else if ($1 == NULL)
  155.                 $$ = $2;
  156.             else {
  157.                 if ($1->type != Node_rule_list)
  158.                     $1 = node($1, Node_rule_list,
  159.                         (NODE*)NULL);
  160.                 $$ = append_right ($1,
  161.                    node($2, Node_rule_list,(NODE *) NULL));
  162.             }
  163.             yyerrok;
  164.         }
  165.     | error    { $$ = NULL; }
  166.     | program error { $$ = NULL; }
  167.     ;
  168.  
  169. rule
  170.     : LEX_BEGIN { io_allowed = 0; }
  171.       action
  172.       {
  173.         if (begin_block) {
  174.             if (begin_block->type != Node_rule_list)
  175.                 begin_block = node(begin_block, Node_rule_list,
  176.                     (NODE *)NULL);
  177.             (void) append_right (begin_block, node(
  178.                 node((NODE *)NULL, Node_rule_node, $3),
  179.                 Node_rule_list, (NODE *)NULL) );
  180.         } else
  181.             begin_block = node((NODE *)NULL, Node_rule_node, $3);
  182.         $$ = NULL;
  183.         io_allowed = 1;
  184.         yyerrok;
  185.       }
  186.     | LEX_END { io_allowed = 0; }
  187.       action
  188.       {
  189.         if (end_block) {
  190.             if (end_block->type != Node_rule_list)
  191.                 end_block = node(end_block, Node_rule_list,
  192.                     (NODE *)NULL);
  193.             (void) append_right (end_block, node(
  194.                 node((NODE *)NULL, Node_rule_node, $3),
  195.                 Node_rule_list, (NODE *)NULL));
  196.         } else
  197.             end_block = node((NODE *)NULL, Node_rule_node, $3);
  198.         $$ = NULL;
  199.         io_allowed = 1;
  200.         yyerrok;
  201.       }
  202.     | LEX_BEGIN statement_term
  203.       {
  204.         warning("BEGIN blocks must have an action part");
  205.         errcount++;
  206.         yyerrok;
  207.       }
  208.     | LEX_END statement_term
  209.       {
  210.         warning("END blocks must have an action part");
  211.         errcount++;
  212.         yyerrok;
  213.       }
  214.     | pattern action
  215.         { $$ = node ($1, Node_rule_node, $2); yyerrok; }
  216.     | action
  217.         { $$ = node ((NODE *)NULL, Node_rule_node, $1); yyerrok; }
  218.     | pattern statement_term
  219.         {
  220.           $$ = node ($1,
  221.                  Node_rule_node,
  222.                  node(node(node(make_number(0.0),
  223.                         Node_field_spec,
  224.                         (NODE *) NULL),
  225.                     Node_expression_list,
  226.                     (NODE *) NULL),
  227.                   Node_K_print,
  228.                   (NODE *) NULL));
  229.           yyerrok;
  230.         }
  231.     | function_prologue function_body
  232.         {
  233.             func_install($1, $2);
  234.             $$ = NULL;
  235.             yyerrok;
  236.         }
  237.     ;
  238.  
  239. func_name
  240.     : NAME
  241.         { $$ = $1; }
  242.     | FUNC_CALL
  243.         { $$ = $1; }
  244.     | lex_builtin
  245.       {
  246.         yyerror("%s() is a built-in function, it cannot be redefined",
  247.             tokstart);
  248.         errcount++;
  249.         /* yyerrok; */
  250.       }
  251.     ;
  252.  
  253. lex_builtin
  254.     : LEX_BUILTIN
  255.     | LEX_LENGTH
  256.     ;
  257.         
  258. function_prologue
  259.     : LEX_FUNCTION 
  260.         {
  261.             param_counter = 0;
  262.         }
  263.       func_name '(' opt_param_list r_paren opt_nls
  264.         {
  265.             $$ = append_right(make_param($3), $5);
  266.             can_return = 1;
  267.         }
  268.     ;
  269.  
  270. function_body
  271.     : l_brace statements r_brace opt_semi
  272.       {
  273.         $$ = $2;
  274.         can_return = 0;
  275.       }
  276.     ;
  277.  
  278.  
  279. pattern
  280.     : exp
  281.         { $$ = $1; }
  282.     | exp comma exp
  283.         { $$ = mkrangenode ( node($1, Node_cond_pair, $3) ); }
  284.     ;
  285.  
  286. regexp
  287.     /*
  288.      * In this rule, want_regexp tells yylex that the next thing
  289.      * is a regexp so it should read up to the closing slash.
  290.      */
  291.     : '/'
  292.         { ++want_regexp; }
  293.       REGEXP '/'
  294.         {
  295.           NODE *n;
  296.  
  297.           getnode(n);
  298.           n->type = Node_regex;
  299.           n->re_exp = make_string($3, strlen($3));
  300.           n->re_reg = mk_re_parse($3, 0);
  301.           n->re_text = NULL;
  302.           n->re_flags = CONST;
  303.           n->re_cnt = 1;
  304.           $$ = n;
  305.         }
  306.     ;
  307.  
  308. action
  309.     : l_brace statements r_brace opt_semi opt_nls
  310.         { $$ = $2 ; }
  311.     | l_brace r_brace opt_semi opt_nls
  312.         { $$ = NULL; }
  313.     ;
  314.  
  315. statements
  316.     : statement
  317.         { $$ = $1; }
  318.     | statements statement
  319.         {
  320.             if ($1 == NULL || $1->type != Node_statement_list)
  321.                 $1 = node($1, Node_statement_list,(NODE *)NULL);
  322.                 $$ = append_right($1,
  323.                 node( $2, Node_statement_list, (NODE *)NULL));
  324.                 yyerrok;
  325.         }
  326.     | error
  327.         { $$ = NULL; }
  328.     | statements error
  329.         { $$ = NULL; }
  330.     ;
  331.  
  332. statement_term
  333.     : nls
  334.     | semi opt_nls
  335.     ;
  336.  
  337. statement
  338.     : semi opt_nls
  339.         { $$ = NULL; }
  340.     | l_brace r_brace
  341.         { $$ = NULL; }
  342.     | l_brace statements r_brace
  343.         { $$ = $2; }
  344.     | if_statement
  345.         { $$ = $1; }
  346.     | LEX_WHILE '(' exp r_paren opt_nls statement
  347.         { $$ = node ($3, Node_K_while, $6); }
  348.     | LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
  349.         { $$ = node ($6, Node_K_do, $3); }
  350.     | LEX_FOR '(' NAME LEX_IN NAME r_paren opt_nls statement
  351.       {
  352.         $$ = node ($8, Node_K_arrayfor, make_for_loop(variable($3,1),
  353.             (NODE *)NULL, variable($5,1)));
  354.       }
  355.     | LEX_FOR '(' opt_exp semi exp semi opt_exp r_paren opt_nls statement
  356.       {
  357.         $$ = node($10, Node_K_for, (NODE *)make_for_loop($3, $5, $7));
  358.       }
  359.     | LEX_FOR '(' opt_exp semi semi opt_exp r_paren opt_nls statement
  360.       {
  361.         $$ = node ($9, Node_K_for,
  362.             (NODE *)make_for_loop($3, (NODE *)NULL, $6));
  363.       }
  364.     | LEX_BREAK statement_term
  365.        /* for break, maybe we'll have to remember where to break to */
  366.         { $$ = node ((NODE *)NULL, Node_K_break, (NODE *)NULL); }
  367.     | LEX_CONTINUE statement_term
  368.        /* similarly */
  369.         { $$ = node ((NODE *)NULL, Node_K_continue, (NODE *)NULL); }
  370.     | print '(' expression_list r_paren output_redir statement_term
  371.         { $$ = node ($3, $1, $5); }
  372.     | print opt_rexpression_list output_redir statement_term
  373.         {
  374.             if ($1 == Node_K_print && $2 == NULL)
  375.                 $2 = node(node(make_number(0.0),
  376.                            Node_field_spec,
  377.                            (NODE *) NULL),
  378.                       Node_expression_list,
  379.                       (NODE *) NULL);
  380.  
  381.             $$ = node ($2, $1, $3);
  382.         }
  383.     | LEX_NEXT opt_exp statement_term
  384.         { NODETYPE type;
  385.  
  386.           if (! io_allowed) yyerror("next used in BEGIN or END action");
  387.           if ($2 && $2 == lookup("file")) {
  388.             if (do_lint)
  389.                 warning("`next file' is a gawk extension");
  390.             else if (strict || do_posix)
  391.                 yyerror("`next file' is a gawk extension");
  392.             type = Node_K_nextfile;
  393.           } else type = Node_K_next;
  394.           $$ = node ((NODE *)NULL, type, (NODE *)NULL);
  395.         }
  396.     | LEX_EXIT opt_exp statement_term
  397.         { $$ = node ($2, Node_K_exit, (NODE *)NULL); }
  398.     | LEX_RETURN
  399.         { if (! can_return) yyerror("return used outside function context"); }
  400.       opt_exp statement_term
  401.         { $$ = node ($3, Node_K_return, (NODE *)NULL); }
  402.     | LEX_DELETE NAME '[' expression_list ']' statement_term
  403.         { $$ = node (variable($2,1), Node_K_delete, $4); }
  404.     | exp statement_term
  405.         { $$ = $1; }
  406.     ;
  407.  
  408. print
  409.     : LEX_PRINT
  410.         { $$ = $1; }
  411.     | LEX_PRINTF
  412.         { $$ = $1; }
  413.     ;
  414.  
  415. if_statement
  416.     : LEX_IF '(' exp r_paren opt_nls statement
  417.       {
  418.         $$ = node($3, Node_K_if, 
  419.             node($6, Node_if_branches, (NODE *)NULL));
  420.       }
  421.     | LEX_IF '(' exp r_paren opt_nls statement
  422.          LEX_ELSE opt_nls statement
  423.         { $$ = node ($3, Node_K_if,
  424.                 node ($6, Node_if_branches, $9)); }
  425.     ;
  426.  
  427. nls
  428.     : NEWLINE
  429.         { want_assign = 0; }
  430.     | nls NEWLINE
  431.     ;
  432.  
  433. opt_nls
  434.     : /* empty */
  435.     | nls
  436.     ;
  437.  
  438. input_redir
  439.     : /* empty */
  440.         { $$ = NULL; }
  441.     | '<' simp_exp
  442.         { $$ = node ($2, Node_redirect_input, (NODE *)NULL); }
  443.     ;
  444.  
  445. output_redir
  446.     : /* empty */
  447.         { $$ = NULL; }
  448.     | '>' exp
  449.         { $$ = node ($2, Node_redirect_output, (NODE *)NULL); }
  450.     | APPEND_OP exp
  451.         { $$ = node ($2, Node_redirect_append, (NODE *)NULL); }
  452.     | '|' exp
  453.         { $$ = node ($2, Node_redirect_pipe, (NODE *)NULL); }
  454.     ;
  455.  
  456. opt_param_list
  457.     : /* empty */
  458.         { $$ = NULL; }
  459.     | param_list
  460.         { $$ = $1; }
  461.     ;
  462.  
  463. param_list
  464.     : NAME
  465.         { $$ = make_param($1); }
  466.     | param_list comma NAME
  467.         { $$ = append_right($1, make_param($3)); yyerrok; }
  468.     | error
  469.         { $$ = NULL; }
  470.     | param_list error
  471.         { $$ = NULL; }
  472.     | param_list comma error
  473.         { $$ = NULL; }
  474.     ;
  475.  
  476. /* optional expression, as in for loop */
  477. opt_exp
  478.     : /* empty */
  479.         { $$ = NULL; }
  480.     | exp
  481.         { $$ = $1; }
  482.     ;
  483.  
  484. opt_rexpression_list
  485.     : /* empty */
  486.         { $$ = NULL; }
  487.     | rexpression_list
  488.         { $$ = $1; }
  489.     ;
  490.  
  491. rexpression_list
  492.     : rexp
  493.         { $$ = node ($1, Node_expression_list, (NODE *)NULL); }
  494.     | rexpression_list comma rexp
  495.       {
  496.         $$ = append_right($1,
  497.             node( $3, Node_expression_list, (NODE *)NULL));
  498.         yyerrok;
  499.       }
  500.     | error
  501.         { $$ = NULL; }
  502.     | rexpression_list error
  503.         { $$ = NULL; }
  504.     | rexpression_list error rexp
  505.         { $$ = NULL; }
  506.     | rexpression_list comma error
  507.         { $$ = NULL; }
  508.     ;
  509.  
  510. opt_expression_list
  511.     : /* empty */
  512.         { $$ = NULL; }
  513.     | expression_list
  514.         { $$ = $1; }
  515.     ;
  516.  
  517. expression_list
  518.     : exp
  519.         { $$ = node ($1, Node_expression_list, (NODE *)NULL); }
  520.     | expression_list comma exp
  521.         {
  522.             $$ = append_right($1,
  523.                 node( $3, Node_expression_list, (NODE *)NULL));
  524.             yyerrok;
  525.         }
  526.     | error
  527.         { $$ = NULL; }
  528.     | expression_list error
  529.         { $$ = NULL; }
  530.     | expression_list error exp
  531.         { $$ = NULL; }
  532.     | expression_list comma error
  533.         { $$ = NULL; }
  534.     ;
  535.  
  536. /* Expressions, not including the comma operator.  */
  537. exp    : variable ASSIGNOP 
  538.         { want_assign = 0; }
  539.       exp
  540.         {
  541.           if (do_lint && $4->type == Node_regex)
  542.             warning("Regular expression on left of assignment.");
  543.           $$ = node ($1, $2, $4);
  544.         }
  545.     | '(' expression_list r_paren LEX_IN NAME
  546.         { $$ = node (variable($5,1), Node_in_array, $2); }
  547.     | exp '|' LEX_GETLINE opt_variable
  548.         {
  549.           $$ = node ($4, Node_K_getline,
  550.              node ($1, Node_redirect_pipein, (NODE *)NULL));
  551.         }
  552.     | LEX_GETLINE opt_variable input_redir
  553.         {
  554.           if (do_lint && ! io_allowed && $3 == NULL)
  555.             warning("non-redirected getline undefined inside BEGIN or END action");
  556.           $$ = node ($2, Node_K_getline, $3);
  557.         }
  558.     | exp LEX_AND exp
  559.         { $$ = node ($1, Node_and, $3); }
  560.     | exp LEX_OR exp
  561.         { $$ = node ($1, Node_or, $3); }
  562.     | exp MATCHOP exp
  563.         {
  564.           if ($1->type == Node_regex)
  565.             warning("Regular expression on left of MATCH operator.");
  566.           $$ = node ($1, $2, mk_rexp($3));
  567.         }
  568.     | regexp
  569.         { $$ = $1; }
  570.     | '!' regexp %prec UNARY
  571.         {
  572.           $$ = node(node(make_number(0.0),
  573.                  Node_field_spec,
  574.                  (NODE *) NULL),
  575.                     Node_nomatch,
  576.                 $2);
  577.         }
  578.     | exp LEX_IN NAME
  579.         { $$ = node (variable($3,1), Node_in_array, $1); }
  580.     | exp RELOP exp
  581.         {
  582.           if (do_lint && $3->type == Node_regex)
  583.             warning("Regular expression on left of comparison.");
  584.           $$ = node ($1, $2, $3);
  585.         }
  586.     | exp '<' exp
  587.         { $$ = node ($1, Node_less, $3); }
  588.     | exp '>' exp
  589.         { $$ = node ($1, Node_greater, $3); }
  590.     | exp '?' exp ':' exp
  591.         { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
  592.     | simp_exp
  593.         { $$ = $1; }
  594.     | exp exp %prec CONCAT_OP
  595.         { $$ = node ($1, Node_concat, $2); }
  596.     ;
  597.  
  598. rexp    
  599.     : variable ASSIGNOP 
  600.         { want_assign = 0; }
  601.       rexp
  602.         { $$ = node ($1, $2, $4); }
  603.     | rexp LEX_AND rexp
  604.         { $$ = node ($1, Node_and, $3); }
  605.     | rexp LEX_OR rexp
  606.         { $$ = node ($1, Node_or, $3); }
  607.     | LEX_GETLINE opt_variable input_redir
  608.         {
  609.           if (do_lint && ! io_allowed && $3 == NULL)
  610.             warning("non-redirected getline undefined inside BEGIN or END action");
  611.           $$ = node ($2, Node_K_getline, $3);
  612.         }
  613.     | regexp
  614.         { $$ = $1; } 
  615.     | '!' regexp %prec UNARY
  616.         { $$ = node((NODE *) NULL, Node_nomatch, $2); }
  617.     | rexp MATCHOP rexp
  618.          { $$ = node ($1, $2, mk_rexp($3)); }
  619.     | rexp LEX_IN NAME
  620.         { $$ = node (variable($3,1), Node_in_array, $1); }
  621.     | rexp RELOP rexp
  622.         { $$ = node ($1, $2, $3); }
  623.     | rexp '?' rexp ':' rexp
  624.         { $$ = node($1, Node_cond_exp, node($3, Node_if_branches, $5));}
  625.     | simp_exp
  626.         { $$ = $1; }
  627.     | rexp rexp %prec CONCAT_OP
  628.         { $$ = node ($1, Node_concat, $2); }
  629.     ;
  630.  
  631. simp_exp
  632.     : non_post_simp_exp
  633.     | post_inc_dec_exp
  634.     /* Binary operators in order of decreasing precedence.  */
  635.     | simp_exp '^' simp_exp
  636.         { $$ = node ($1, Node_exp, $3); }
  637.     | simp_exp '*' simp_exp
  638.         { $$ = node ($1, Node_times, $3); }
  639.     | simp_exp '/' simp_exp
  640.         { $$ = node ($1, Node_quotient, $3); }
  641.     | simp_exp '%' simp_exp
  642.         { $$ = node ($1, Node_mod, $3); }
  643.     | simp_exp '+' simp_exp
  644.         { $$ = node ($1, Node_plus, $3); }
  645.     | simp_exp '-' simp_exp
  646.         { $$ = node ($1, Node_minus, $3); }
  647.     ;
  648.  
  649. non_post_simp_exp
  650.     : '!' simp_exp %prec UNARY
  651.         { $$ = node ($2, Node_not,(NODE *) NULL); }
  652.     | '(' exp r_paren
  653.         { $$ = $2; }
  654.     | LEX_BUILTIN
  655.         { 
  656.         if (! io_allowed && strcmp(tokstart, "nextfile") == 0)
  657.             yyerror("nextfile() is illegal in BEGIN and END");
  658.         }
  659.       '(' opt_expression_list r_paren
  660.         { $$ = snode ($4, Node_builtin, (int) $1); }
  661.     | LEX_LENGTH '(' opt_expression_list r_paren
  662.         { $$ = snode ($3, Node_builtin, (int) $1); }
  663.     | LEX_LENGTH
  664.       {
  665.         if (do_lint)
  666.             warning("call of `length' without parentheses is not portable");
  667.         $$ = snode ((NODE *)NULL, Node_builtin, (int) $1);
  668.         if (do_posix)
  669.             warning( "call of `length' without parentheses is deprecated by POSIX");
  670.       }
  671.     | FUNC_CALL '(' opt_expression_list r_paren
  672.       {
  673.         $$ = node ($3, Node_func_call, make_string($1, strlen($1)));
  674.       }
  675.     | INCREMENT variable
  676.         { $$ = node ($2, Node_preincrement, (NODE *)NULL); }
  677.     | DECREMENT variable
  678.         { $$ = node ($2, Node_predecrement, (NODE *)NULL); }
  679.     | YNUMBER
  680.         { $$ = $1; }
  681.     | YSTRING
  682.         { $$ = $1; }
  683.  
  684.     | '-' simp_exp    %prec UNARY
  685.         { if ($2->type == Node_val) {
  686.             $2->numbr = -(force_number($2));
  687.             $$ = $2;
  688.           } else
  689.             $$ = node ($2, Node_unary_minus, (NODE *)NULL);
  690.         }
  691.     | '+' simp_exp    %prec UNARY
  692.         { $$ = $2; }
  693.     ;
  694.  
  695. post_inc_dec_exp
  696.     : variable INCREMENT
  697.         { $$ = node ($1, Node_postincrement, (NODE *)NULL); }
  698.     | variable DECREMENT
  699.         { $$ = node ($1, Node_postdecrement, (NODE *)NULL); }
  700.     | variable
  701.     ;
  702.  
  703. opt_variable
  704.     : /* empty */
  705.         { $$ = NULL; }
  706.     | variable
  707.         { $$ = $1; }
  708.     ;
  709.  
  710. variable
  711.     : NAME
  712.         { $$ = variable($1,1); }
  713.     | NAME '[' expression_list ']'
  714.         {
  715.         if ($3->rnode == NULL) {
  716.             $$ = node (variable($1,1), Node_subscript, $3->lnode);
  717.             freenode($3);
  718.         } else
  719.             $$ = node (variable($1,1), Node_subscript, $3);
  720.         }
  721.     | '$' non_post_simp_exp
  722.         { $$ = node ($2, Node_field_spec, (NODE *)NULL); }
  723.     | '$' variable
  724.         { $$ = node ($2, Node_field_spec, (NODE *)NULL); }
  725.     ;
  726.  
  727. l_brace
  728.     : '{' opt_nls
  729.     ;
  730.  
  731. r_brace
  732.     : '}' opt_nls    { yyerrok; }
  733.     ;
  734.  
  735. r_paren
  736.     : ')' { yyerrok; }
  737.     ;
  738.  
  739. opt_semi
  740.     : /* empty */
  741.     | semi
  742.     ;
  743.  
  744. semi
  745.     : ';'    { yyerrok; want_assign = 0; }
  746.     ;
  747.  
  748. comma    : ',' opt_nls    { yyerrok; }
  749.     ;
  750.  
  751. %%
  752.  
  753. struct token {
  754.     char *operator;        /* text to match */
  755.     NODETYPE value;        /* node type */
  756.     int class;        /* lexical class */
  757.     unsigned flags;        /* # of args. allowed and compatability */
  758. #    define    ARGS    0xFF    /* 0, 1, 2, 3 args allowed (any combination */
  759. #    define    A(n)    (1<<(n))
  760. #    define    VERSION    0xFF00    /* old awk is zero */
  761. #    define    NOT_OLD        0x0100    /* feature not in old awk */
  762. #    define    NOT_POSIX    0x0200    /* feature not in POSIX */
  763. #    define    GAWKX        0x0400    /* gawk extension */
  764.     NODE *(*ptr) ();    /* function that implements this keyword */
  765. };
  766.  
  767. extern NODE
  768.     *do_exp(),    *do_getline(),    *do_index(),    *do_length(),
  769.     *do_sqrt(),    *do_log(),    *do_sprintf(),    *do_substr(),
  770.     *do_split(),    *do_system(),    *do_int(),    *do_close(),
  771.     *do_atan2(),    *do_sin(),    *do_cos(),    *do_rand(),
  772.     *do_srand(),    *do_match(),    *do_tolower(),    *do_toupper(),
  773.     *do_sub(),    *do_gsub(),    *do_strftime(),    *do_systime();
  774.  
  775. /* Tokentab is sorted ascii ascending order, so it can be binary searched. */
  776.  
  777. static struct token tokentab[] = {
  778. {"BEGIN",    Node_illegal,     LEX_BEGIN,    0,        0},
  779. {"END",        Node_illegal,     LEX_END,    0,        0},
  780. {"atan2",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2),    do_atan2},
  781. {"break",    Node_K_break,     LEX_BREAK,    0,        0},
  782. {"close",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_close},
  783. {"continue",    Node_K_continue, LEX_CONTINUE,    0,        0},
  784. {"cos",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_cos},
  785. {"delete",    Node_K_delete,     LEX_DELETE,    NOT_OLD,    0},
  786. {"do",        Node_K_do,     LEX_DO,    NOT_OLD,    0},
  787. {"else",    Node_illegal,     LEX_ELSE,    0,        0},
  788. {"exit",    Node_K_exit,     LEX_EXIT,    0,        0},
  789. {"exp",        Node_builtin,     LEX_BUILTIN,    A(1),        do_exp},
  790. {"for",        Node_K_for,     LEX_FOR,    0,        0},
  791. {"func",    Node_K_function, LEX_FUNCTION,    NOT_POSIX|NOT_OLD,    0},
  792. {"function",    Node_K_function, LEX_FUNCTION,    NOT_OLD,    0},
  793. {"getline",    Node_K_getline,     LEX_GETLINE,    NOT_OLD,    0},
  794. {"gsub",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2)|A(3), do_gsub},
  795. {"if",        Node_K_if,     LEX_IF,    0,        0},
  796. {"in",        Node_illegal,     LEX_IN,    0,        0},
  797. {"index",    Node_builtin,     LEX_BUILTIN,    A(2),        do_index},
  798. {"int",        Node_builtin,     LEX_BUILTIN,    A(1),        do_int},
  799. {"length",    Node_builtin,     LEX_LENGTH,    A(0)|A(1),    do_length},
  800. {"log",        Node_builtin,     LEX_BUILTIN,    A(1),        do_log},
  801. {"match",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2),    do_match},
  802. {"next",    Node_K_next,     LEX_NEXT,    0,        0},
  803. {"print",    Node_K_print,     LEX_PRINT,    0,        0},
  804. {"printf",    Node_K_printf,     LEX_PRINTF,    0,        0},
  805. {"rand",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(0),    do_rand},
  806. {"return",    Node_K_return,     LEX_RETURN,    NOT_OLD,    0},
  807. {"sin",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_sin},
  808. {"split",    Node_builtin,     LEX_BUILTIN,    A(2)|A(3),    do_split},
  809. {"sprintf",    Node_builtin,     LEX_BUILTIN,    0,        do_sprintf},
  810. {"sqrt",    Node_builtin,     LEX_BUILTIN,    A(1),        do_sqrt},
  811. {"srand",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(0)|A(1), do_srand},
  812. {"strftime",    Node_builtin,     LEX_BUILTIN,    GAWKX|A(1)|A(2), do_strftime},
  813. {"sub",        Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(2)|A(3), do_sub},
  814. {"substr",    Node_builtin,     LEX_BUILTIN,    A(2)|A(3),    do_substr},
  815. {"system",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_system},
  816. {"systime",    Node_builtin,     LEX_BUILTIN,    GAWKX|A(0),    do_systime},
  817. {"tolower",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_tolower},
  818. {"toupper",    Node_builtin,     LEX_BUILTIN,    NOT_OLD|A(1),    do_toupper},
  819. {"while",    Node_K_while,     LEX_WHILE,    0,        0},
  820. };
  821.  
  822. /* VARARGS0 */
  823. /* static void
  824. yyerror(va_alist)
  825. va_dcl
  826. {
  827.     va_list args;
  828.     char *mesg;
  829.     register char *bp, *cp;
  830.     char *scan;
  831.     char buf[120];
  832.  
  833.     errcount++;
  834.     /* Find the current line in the input file */
  835.     if (lexptr) {
  836.         if (!thisline) {
  837.             for (cp=lexeme; cp != lexptr_begin && *cp != '\n'; --cp)
  838.                 ;
  839.             if (*cp == '\n')
  840.                 cp++;
  841.             thisline = cp;
  842.         }
  843.         /* NL isn't guaranteed */
  844.         bp = lexeme;
  845.         while (bp < lexend && *bp && *bp != '\n')
  846.             bp++;
  847.     } else {
  848.         thisline = "(END OF FILE)";
  849.         bp = thisline + 13;
  850.     }
  851.     msg("%.*s", (int) (bp - thisline), thisline);
  852.     bp = buf;
  853.     cp = buf + sizeof(buf) - 24;    /* 24 more than longest msg. input */
  854.     if (lexptr) {
  855.         scan = thisline;
  856.         while (bp < cp && scan < lexeme)
  857.             if (*scan++ == '\t')
  858.                 *bp++ = '\t';
  859.             else
  860.                 *bp++ = ' ';
  861.         *bp++ = '^';
  862.         *bp++ = ' ';
  863.     }
  864.     va_start( args);
  865.     mesg = va_arg(args, char *);
  866.     strcpy(bp, mesg);
  867.     err("", buf, args);
  868.     va_end(args);
  869.     exit(2);
  870. } */
  871.  
  872. static char *
  873. get_src_buf()
  874. {
  875.     static int samefile = 0;
  876.     static int nextfile = 0;
  877.     static char *buf = NULL;
  878.     static int fd;
  879.     int n;
  880.     register char *scan;
  881.     static int len = 0;
  882.     static int did_newline = 0;
  883. #    define    SLOP    128    /* enough space to hold most source lines */
  884.  
  885.     if (cmdline_src) {
  886.         if (len == 0) {
  887.             len = strlen(cmdline_src);
  888.             if (len == 0)
  889.                 cmdline_src = NULL;
  890.             sourceline = 1;
  891.             lexptr = lexptr_begin = cmdline_src;
  892.             lexend = lexptr + len;
  893.         } else if (!did_newline && *(lexptr-1) != '\n') {
  894.             /*
  895.              * The following goop is to ensure that the source
  896.              * ends with a newline and that the entire current
  897.              * line is available for error messages.
  898.              */
  899.             int offset;
  900.  
  901.             did_newline = 1;
  902.             offset = lexptr - lexeme;
  903.             for (scan = lexeme; scan > lexptr_begin; scan--)
  904.                 if (*scan == '\n') {
  905.                     scan++;
  906.                     break;
  907.                 }
  908.             len = lexptr - scan;
  909.             emalloc(buf, char *, len+1, "get_src_buf");
  910.             memcpy(buf, scan, len);
  911.             thisline = buf;
  912.             lexptr = buf + len;
  913.             *lexptr = '\n';
  914.             lexeme = lexptr - offset;
  915.             lexptr_begin = buf;
  916.             lexend = lexptr + 1;
  917.         } else
  918.             lexeme = lexptr = lexptr_begin = NULL;
  919.         return lexptr;
  920.     }
  921.     if (!samefile) {
  922.         source = srcfiles[nextfile];
  923.         if (source == NULL) {
  924.             if (buf)
  925.                 free(buf);
  926.             return lexeme = lexptr = lexptr_begin = NULL;
  927.         }
  928.         fd = pathopen(source);
  929.         if (fd == -1)
  930.             fatal("can't open source file \"%s\" for reading (%s)",
  931.                 source, strerror(errno));
  932.         len = optimal_bufsize(fd);
  933.         if (buf)
  934.             free(buf);
  935.         emalloc(buf, char *, len + SLOP, "get_src_buf");
  936.         lexptr_begin = buf + SLOP;
  937.         samefile = 1;
  938.         sourceline = 1;
  939.     } else {
  940.         /*
  941.          * Here, we retain the current source line (up to length SLOP)
  942.          * in the beginning of the buffer that was overallocated above
  943.          */
  944.         int offset;
  945.         int linelen;
  946.  
  947.         offset = lexptr - lexeme;
  948.         for (scan = lexeme; scan > lexptr_begin; scan--)
  949.             if (*scan == '\n') {
  950.                 scan++;
  951.                 break;
  952.             }
  953.         linelen = lexptr - scan;
  954.         if (linelen > SLOP)
  955.             len = SLOP;
  956.         thisline = buf + SLOP - linelen;
  957.         memcpy(thisline, scan, linelen);
  958.         lexeme = buf + SLOP - offset;
  959.         lexptr_begin = thisline;
  960.     }
  961.     n = read(fd, buf + SLOP, len);
  962.     if (n == -1)
  963.         fatal("can't read sourcefile \"%s\" (%s)",
  964.             source, strerror(errno));
  965.     if (n == 0) {
  966.         samefile = 0;
  967.         nextfile++;
  968.         return get_src_buf();
  969.     }
  970.     lexptr = buf + SLOP;
  971.     lexend = lexptr + n;
  972.     return buf;
  973. }
  974.  
  975. #define    tokadd(x) (*token++ = (x), token == tokend ? tokexpand() : token)
  976.  
  977. char *
  978. tokexpand()
  979. {
  980.     static int toksize = 60;
  981.     int tokoffset;
  982.  
  983.     tokoffset = token - tokstart;
  984.     toksize *= 2;
  985.     if (tokstart)
  986.         erealloc(tokstart, char *, toksize, "tokexpand");
  987.     else
  988.         emalloc(tokstart, char *, toksize, "tokexpand");
  989.     tokend = tokstart + toksize;
  990.     token = tokstart + tokoffset;
  991.     return token;
  992. }
  993.  
  994. #ifdef DEBUG
  995. char
  996. nextc() {
  997.     if (lexptr && lexptr < lexend)
  998.         return *lexptr++;
  999.     if (get_src_buf())
  1000.         return *lexptr++;
  1001.     return '\0';
  1002. }
  1003. #else
  1004. #define    nextc()    ((lexptr && lexptr < lexend) ? \
  1005.             *lexptr++ : \
  1006.             (get_src_buf() ? *lexptr++ : '\0') \
  1007.         )
  1008. #endif
  1009. #define pushback() (lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr)
  1010.  
  1011. /*
  1012.  * Read the input and turn it into tokens.
  1013.  */
  1014.  
  1015. static int
  1016. yylex()
  1017. {
  1018.     register int c;
  1019.     int seen_e = 0;        /* These are for numbers */
  1020.     int seen_point = 0;
  1021.     int esc_seen;        /* for literal strings */
  1022.     int low, mid, high;
  1023.     static int did_newline = 0;
  1024.     char *tokkey;
  1025.  
  1026.     if (!nextc())
  1027.         return 0;
  1028.     pushback();
  1029.     lexeme = lexptr;
  1030.     thisline = NULL;
  1031.     if (want_regexp) {
  1032.         int in_brack = 0;
  1033.  
  1034.         want_regexp = 0;
  1035.         token = tokstart;
  1036.         while ((c = nextc()) != 0) {
  1037.             switch (c) {
  1038.             case '[':
  1039.                 in_brack = 1;
  1040.                 break;
  1041.             case ']':
  1042.                 in_brack = 0;
  1043.                 break;
  1044.             case '\\':
  1045.                 if ((c = nextc()) == '\0') {
  1046.                     yyerror("unterminated regexp ends with \\ at end of file");
  1047.                 } else if (c == '\n') {
  1048.                     sourceline++;
  1049.                     continue;
  1050.                 } else
  1051.                     tokadd('\\');
  1052.                 break;
  1053.             case '/':    /* end of the regexp */
  1054.                 if (in_brack)
  1055.                     break;
  1056.  
  1057.                 pushback();
  1058.                 tokadd('\0');
  1059.                 yylval.sval = tokstart;
  1060.                 return REGEXP;
  1061.             case '\n':
  1062.                 pushback();
  1063.                 yyerror("unterminated regexp");
  1064.             case '\0':
  1065.                 yyerror("unterminated regexp at end of file");
  1066.             }
  1067.             tokadd(c);
  1068.         }
  1069.     }
  1070. retry:
  1071.     while ((c = nextc()) == ' ' || c == '\t')
  1072.         ;
  1073.  
  1074.     lexeme = lexptr-1;
  1075.     thisline = NULL;
  1076.     token = tokstart;
  1077.     yylval.nodetypeval = Node_illegal;
  1078.  
  1079.     switch (c) {
  1080.     case 0:
  1081.         return 0;
  1082.  
  1083.     case '\n':
  1084.         sourceline++;
  1085.         return NEWLINE;
  1086.  
  1087.     case '#':        /* it's a comment */
  1088.         while ((c = nextc()) != '\n') {
  1089.             if (c == '\0')
  1090.                 return 0;
  1091.         }
  1092.         sourceline++;
  1093.         return NEWLINE;
  1094.  
  1095.     case '\\':
  1096. #ifdef RELAXED_CONTINUATION
  1097.         if (!strict) {    /* strip trailing white-space and/or comment */
  1098.             while ((c = nextc()) == ' ' || c == '\t') continue;
  1099.             if (c == '#')
  1100.                 while ((c = nextc()) != '\n') if (!c) break;
  1101.             pushback();
  1102.         }
  1103. #endif /*RELAXED_CONTINUATION*/
  1104.         if (nextc() == '\n') {
  1105.             sourceline++;
  1106.             goto retry;
  1107.         } else
  1108.             yyerror("inappropriate use of backslash");
  1109.         break;
  1110.  
  1111.     case '$':
  1112.         want_assign = 1;
  1113.         return '$';
  1114.  
  1115.     case ')':
  1116.     case ']':
  1117.     case '(':    
  1118.     case '[':
  1119.     case ';':
  1120.     case ':':
  1121.     case '?':
  1122.     case '{':
  1123.     case ',':
  1124.         return c;
  1125.  
  1126.     case '*':
  1127.         if ((c = nextc()) == '=') {
  1128.             yylval.nodetypeval = Node_assign_times;
  1129.             return ASSIGNOP;
  1130.         } else if (do_posix) {
  1131.             pushback();
  1132.             return '*';
  1133.         } else if (c == '*') {
  1134.             /* make ** and **= aliases for ^ and ^= */
  1135.             static int did_warn_op = 0, did_warn_assgn = 0;
  1136.  
  1137.             if (nextc() == '=') {
  1138.                 if (do_lint && ! did_warn_assgn) {
  1139.                     did_warn_assgn = 1;
  1140.                     warning("**= is not allowed by POSIX");
  1141.                 }
  1142.                 yylval.nodetypeval = Node_assign_exp;
  1143.                 return ASSIGNOP;
  1144.             } else {
  1145.                 pushback();
  1146.                 if (do_lint && ! did_warn_op) {
  1147.                     did_warn_op = 1;
  1148.                     warning("** is not allowed by POSIX");
  1149.                 }
  1150.                 return '^';
  1151.             }
  1152.         }
  1153.         pushback();
  1154.         return '*';
  1155.  
  1156.     case '/':
  1157.         if (want_assign) {
  1158.             if (nextc() == '=') {
  1159.                 yylval.nodetypeval = Node_assign_quotient;
  1160.                 return ASSIGNOP;
  1161.             }
  1162.             pushback();
  1163.         }
  1164.         return '/';
  1165.  
  1166.     case '%':
  1167.         if (nextc() == '=') {
  1168.             yylval.nodetypeval = Node_assign_mod;
  1169.             return ASSIGNOP;
  1170.         }
  1171.         pushback();
  1172.         return '%';
  1173.  
  1174.     case '^':
  1175.     {
  1176.         static int did_warn_op = 0, did_warn_assgn = 0;
  1177.  
  1178.         if (nextc() == '=') {
  1179.  
  1180.             if (do_lint && ! did_warn_assgn) {
  1181.                 did_warn_assgn = 1;
  1182.                 warning("operator `^=' is not supported in old awk");
  1183.             }
  1184.             yylval.nodetypeval = Node_assign_exp;
  1185.             return ASSIGNOP;
  1186.         }
  1187.         pushback();
  1188.         if (do_lint && ! did_warn_op) {
  1189.             did_warn_op = 1;
  1190.             warning("operator `^' is not supported in old awk");
  1191.         }
  1192.         return '^';
  1193.     }
  1194.  
  1195.     case '+':
  1196.         if ((c = nextc()) == '=') {
  1197.             yylval.nodetypeval = Node_assign_plus;
  1198.             return ASSIGNOP;
  1199.         }
  1200.         if (c == '+')
  1201.             return INCREMENT;
  1202.         pushback();
  1203.         return '+';
  1204.  
  1205.     case '!':
  1206.         if ((c = nextc()) == '=') {
  1207.             yylval.nodetypeval = Node_notequal;
  1208.             return RELOP;
  1209.         }
  1210.         if (c == '~') {
  1211.             yylval.nodetypeval = Node_nomatch;
  1212.             want_assign = 0;
  1213.             return MATCHOP;
  1214.         }
  1215.         pushback();
  1216.         return '!';
  1217.  
  1218.     case '<':
  1219.         if (nextc() == '=') {
  1220.             yylval.nodetypeval = Node_leq;
  1221.             return RELOP;
  1222.         }
  1223.         yylval.nodetypeval = Node_less;
  1224.         pushback();
  1225.         return '<';
  1226.  
  1227.     case '=':
  1228.         if (nextc() == '=') {
  1229.             yylval.nodetypeval = Node_equal;
  1230.             return RELOP;
  1231.         }
  1232.         yylval.nodetypeval = Node_assign;
  1233.         pushback();
  1234.         return ASSIGNOP;
  1235.  
  1236.     case '>':
  1237.         if ((c = nextc()) == '=') {
  1238.             yylval.nodetypeval = Node_geq;
  1239.             return RELOP;
  1240.         } else if (c == '>') {
  1241.             yylval.nodetypeval = Node_redirect_append;
  1242.             return APPEND_OP;
  1243.         }
  1244.         yylval.nodetypeval = Node_greater;
  1245.         pushback();
  1246.         return '>';
  1247.  
  1248.     case '~':
  1249.         yylval.nodetypeval = Node_match;
  1250.         want_assign = 0;
  1251.         return MATCHOP;
  1252.  
  1253.     case '}':
  1254.         /*
  1255.          * Added did newline stuff.  Easier than
  1256.          * hacking the grammar
  1257.          */
  1258.         if (did_newline) {
  1259.             did_newline = 0;
  1260.             return c;
  1261.         }
  1262.         did_newline++;
  1263.         --lexptr;    /* pick up } next time */
  1264.         return NEWLINE;
  1265.  
  1266.     case '"':
  1267.         esc_seen = 0;
  1268.         while ((c = nextc()) != '"') {
  1269.             if (c == '\n') {
  1270.                 pushback();
  1271.                 yyerror("unterminated string");
  1272.             }
  1273.             if (c == '\\') {
  1274.                 c = nextc();
  1275.                 if (c == '\n') {
  1276.                     sourceline++;
  1277.                     continue;
  1278.                 }
  1279.                 esc_seen = 1;
  1280.                 tokadd('\\');
  1281.             }
  1282.             if (c == '\0') {
  1283.                 pushback();
  1284.                 yyerror("unterminated string");
  1285.             }
  1286.             tokadd(c);
  1287.         }
  1288.         yylval.nodeval = make_str_node(tokstart,
  1289.                     token - tokstart, esc_seen ? SCAN : 0);
  1290.         yylval.nodeval->flags |= PERM;
  1291.         return YSTRING;
  1292.  
  1293.     case '-':
  1294.         if ((c = nextc()) == '=') {
  1295.             yylval.nodetypeval = Node_assign_minus;
  1296.             return ASSIGNOP;
  1297.         }
  1298.         if (c == '-')
  1299.             return DECREMENT;
  1300.         pushback();
  1301.         return '-';
  1302.  
  1303.     case '.':
  1304.         c = nextc();
  1305.         pushback();
  1306.         if (!isdigit(c))
  1307.             return '.';
  1308.         else
  1309.             c = '.';    /* FALL THROUGH */
  1310.     case '0':
  1311.     case '1':
  1312.     case '2':
  1313.     case '3':
  1314.     case '4':
  1315.     case '5':
  1316.     case '6':
  1317.     case '7':
  1318.     case '8':
  1319.     case '9':
  1320.         /* It's a number */
  1321.         for (;;) {
  1322.             int gotnumber = 0;
  1323.  
  1324.             tokadd(c);
  1325.             switch (c) {
  1326.             case '.':
  1327.                 if (seen_point) {
  1328.                     gotnumber++;
  1329.                     break;
  1330.                 }
  1331.                 ++seen_point;
  1332.                 break;
  1333.             case 'e':
  1334.             case 'E':
  1335.                 if (seen_e) {
  1336.                     gotnumber++;
  1337.                     break;
  1338.                 }
  1339.                 ++seen_e;
  1340.                 if ((c = nextc()) == '-' || c == '+')
  1341.                     tokadd(c);
  1342.                 else
  1343.                     pushback();
  1344.                 break;
  1345.             case '0':
  1346.             case '1':
  1347.             case '2':
  1348.             case '3':
  1349.             case '4':
  1350.             case '5':
  1351.             case '6':
  1352.             case '7':
  1353.             case '8':
  1354.             case '9':
  1355.                 break;
  1356.             default:
  1357.                 gotnumber++;
  1358.             }
  1359.             if (gotnumber)
  1360.                 break;
  1361.             c = nextc();
  1362.         }
  1363.         pushback();
  1364.         yylval.nodeval = make_number(atof(tokstart));
  1365.         yylval.nodeval->flags |= PERM;
  1366.         return YNUMBER;
  1367.  
  1368.     case '&':
  1369.         if ((c = nextc()) == '&') {
  1370.             yylval.nodetypeval = Node_and;
  1371.             for (;;) {
  1372.                 c = nextc();
  1373.                 if (c == '\0')
  1374.                     break;
  1375.                 if (c == '#') {
  1376.                     while ((c = nextc()) != '\n' && c != '\0')
  1377.                         ;
  1378.                     if (c == '\0')
  1379.                         break;
  1380.                 }
  1381.                 if (c == '\n')
  1382.                     sourceline++;
  1383.                 if (! isspace(c)) {
  1384.                     pushback();
  1385.                     break;
  1386.                 }
  1387.             }
  1388.             want_assign = 0;
  1389.             return LEX_AND;
  1390.         }
  1391.         pushback();
  1392.         return '&';
  1393.  
  1394.     case '|':
  1395.         if ((c = nextc()) == '|') {
  1396.             yylval.nodetypeval = Node_or;
  1397.             for (;;) {
  1398.                 c = nextc();
  1399.                 if (c == '\0')
  1400.                     break;
  1401.                 if (c == '#') {
  1402.                     while ((c = nextc()) != '\n' && c != '\0')
  1403.                         ;
  1404.                     if (c == '\0')
  1405.                         break;
  1406.                 }
  1407.                 if (c == '\n')
  1408.                     sourceline++;
  1409.                 if (! isspace(c)) {
  1410.                     pushback();
  1411.                     break;
  1412.                 }
  1413.             }
  1414.             want_assign = 0;
  1415.             return LEX_OR;
  1416.         }
  1417.         pushback();
  1418.         return '|';
  1419.     }
  1420.  
  1421.     if (c != '_' && ! isalpha(c))
  1422.         yyerror("Invalid char '%c' in expression\n", c);
  1423.  
  1424.     /* it's some type of name-type-thing.  Find its length */
  1425.     token = tokstart;
  1426.     while (is_identchar(c)) {
  1427.         tokadd(c);
  1428.         c = nextc();
  1429.     }
  1430.     tokadd('\0');
  1431.     emalloc(tokkey, char *, token - tokstart, "yylex");
  1432.     memcpy(tokkey, tokstart, token - tokstart);
  1433.     pushback();
  1434.  
  1435.     /* See if it is a special token.  */
  1436.     low = 0;
  1437.     high = (sizeof (tokentab) / sizeof (tokentab[0])) - 1;
  1438.     while (low <= high) {
  1439.         int i/* , c */;
  1440.  
  1441.         mid = (low + high) / 2;
  1442.         c = *tokstart - tokentab[mid].operator[0];
  1443.         i = c ? c : strcmp (tokstart, tokentab[mid].operator);
  1444.  
  1445.         if (i < 0) {        /* token < mid */
  1446.             high = mid - 1;
  1447.         } else if (i > 0) {    /* token > mid */
  1448.             low = mid + 1;
  1449.         } else {
  1450.             if (do_lint) {
  1451.                 if (tokentab[mid].flags & GAWKX)
  1452.                     warning("%s() is a gawk extension",
  1453.                         tokentab[mid].operator);
  1454.                 if (tokentab[mid].flags & NOT_POSIX)
  1455.                     warning("POSIX does not allow %s",
  1456.                         tokentab[mid].operator);
  1457.                 if (tokentab[mid].flags & NOT_OLD)
  1458.                     warning("%s is not supported in old awk",
  1459.                         tokentab[mid].operator);
  1460.             }
  1461.             if ((strict && (tokentab[mid].flags & GAWKX))
  1462.                 || (do_posix && (tokentab[mid].flags & NOT_POSIX)))
  1463.                 break;
  1464.             if (tokentab[mid].class == LEX_BUILTIN
  1465.                 || tokentab[mid].class == LEX_LENGTH
  1466.                )
  1467.                 yylval.lval = mid;
  1468.             else
  1469.                 yylval.nodetypeval = tokentab[mid].value;
  1470.  
  1471.             return tokentab[mid].class;
  1472.         }
  1473.     }
  1474.  
  1475.     yylval.sval = tokkey;
  1476.     if (*lexptr == '(')
  1477.         return FUNC_CALL;
  1478.     else {
  1479.         want_assign = 1;
  1480.         return NAME;
  1481.     }
  1482. }
  1483.  
  1484. static NODE *
  1485. node_common(op)
  1486. NODETYPE op;
  1487. {
  1488.     register NODE *r;
  1489.  
  1490.     getnode(r);
  1491.     r->type = op;
  1492.     r->flags = MALLOC;
  1493.     /* if lookahead is NL, lineno is 1 too high */
  1494.     if (lexeme && *lexeme == '\n')
  1495.         r->source_line = sourceline - 1;
  1496.     else
  1497.         r->source_line = sourceline;
  1498.     r->source_file = source;
  1499.     return r;
  1500. }
  1501.  
  1502. /*
  1503.  * This allocates a node with defined lnode and rnode. 
  1504.  */
  1505. NODE *
  1506. node(left, op, right)
  1507. NODE *left, *right;
  1508. NODETYPE op;
  1509. {
  1510.     register NODE *r;
  1511.  
  1512.     r = node_common(op);
  1513.     r->lnode = left;
  1514.     r->rnode = right;
  1515.     return r;
  1516. }
  1517.  
  1518. /*
  1519.  * This allocates a node with defined subnode and proc for builtin functions
  1520.  * Checks for arg. count and supplies defaults where possible.
  1521.  */
  1522. static NODE *
  1523. snode(subn, op, idx)
  1524. NODETYPE op;
  1525. int idx;
  1526. NODE *subn;
  1527. {
  1528.     register NODE *r;
  1529.     register NODE *n;
  1530.     int nexp = 0;
  1531.     int args_allowed;
  1532.  
  1533.     r = node_common(op);
  1534.  
  1535.     /* traverse expression list to see how many args. given */
  1536.     for (n= subn; n; n= n->rnode) {
  1537.         nexp++;
  1538.         if (nexp > 3)
  1539.             break;
  1540.     }
  1541.  
  1542.     /* check against how many args. are allowed for this builtin */
  1543.     args_allowed = tokentab[idx].flags & ARGS;
  1544.     if (args_allowed && !(args_allowed & A(nexp)))
  1545.         fatal("%s() cannot have %d argument%c",
  1546.             tokentab[idx].operator, nexp, nexp == 1 ? ' ' : 's');
  1547.  
  1548.     r->proc = tokentab[idx].ptr;
  1549.  
  1550.     /* special case processing for a few builtins */
  1551.     if (nexp == 0 && r->proc == do_length) {
  1552.         subn = node(node(make_number(0.0),Node_field_spec,(NODE *)NULL),
  1553.                     Node_expression_list,
  1554.                 (NODE *) NULL);
  1555.     } else if (r->proc == do_match) {
  1556.         if (subn->rnode->lnode->type != Node_regex)
  1557.             subn->rnode->lnode = mk_rexp(subn->rnode->lnode);
  1558.     } else if (r->proc == do_sub || r->proc == do_gsub) {
  1559.         if (subn->lnode->type != Node_regex)
  1560.             subn->lnode = mk_rexp(subn->lnode);
  1561.         if (nexp == 2)
  1562.             append_right(subn, node(node(make_number(0.0),
  1563.                              Node_field_spec,
  1564.                              (NODE *) NULL),
  1565.                             Node_expression_list,
  1566.                         (NODE *) NULL));
  1567.         else if (do_lint && subn->rnode->rnode->lnode->type == Node_val)
  1568.             warning("string literal as last arg of substitute");
  1569.     } else if (r->proc == do_split) {
  1570.         if (nexp == 2)
  1571.             append_right(subn,
  1572.                 node(FS_node, Node_expression_list, (NODE *) NULL));
  1573.         n = subn->rnode->rnode->lnode;
  1574.         if (n->type != Node_regex)
  1575.             subn->rnode->rnode->lnode = mk_rexp(n);
  1576.         if (nexp == 2)
  1577.             subn->rnode->rnode->lnode->re_flags |= FS_DFLT;
  1578.     }
  1579.  
  1580.     r->subnode = subn;
  1581.     return r;
  1582. }
  1583.  
  1584. /*
  1585.  * This allocates a Node_line_range node with defined condpair and
  1586.  * zeroes the trigger word to avoid the temptation of assuming that calling
  1587.  * 'node( foo, Node_line_range, 0)' will properly initialize 'triggered'. 
  1588.  */
  1589. /* Otherwise like node() */
  1590. static NODE *
  1591. mkrangenode(cpair)
  1592. NODE *cpair;
  1593. {
  1594.     register NODE *r;
  1595.  
  1596.     getnode(r);
  1597.     r->type = Node_line_range;
  1598.     r->condpair = cpair;
  1599.     r->triggered = 0;
  1600.     return r;
  1601. }
  1602.  
  1603. /* Build a for loop */
  1604. static NODE *
  1605. make_for_loop(init, cond, incr)
  1606. NODE *init, *cond, *incr;
  1607. {
  1608.     register FOR_LOOP_HEADER *r;
  1609.     NODE *n;
  1610.  
  1611.     emalloc(r, FOR_LOOP_HEADER *, sizeof(FOR_LOOP_HEADER), "make_for_loop");
  1612.     getnode(n);
  1613.     n->type = Node_illegal;
  1614.     r->init = init;
  1615.     r->cond = cond;
  1616.     r->incr = incr;
  1617.     n->sub.nodep.r.hd = r;
  1618.     return n;
  1619. }
  1620.  
  1621. /*
  1622.  * Install a name in the symbol table, even if it is already there.
  1623.  * Caller must check against redefinition if that is desired. 
  1624.  */
  1625. NODE *
  1626. install(name, value)
  1627. char *name;
  1628. NODE *value;
  1629. {
  1630.     register NODE *hp;
  1631.     register int len, bucket;
  1632.  
  1633.     len = strlen(name);
  1634.     bucket = hash(name, len);
  1635.     getnode(hp);
  1636.     hp->type = Node_hashnode;
  1637.     hp->hnext = variables[bucket];
  1638.     variables[bucket] = hp;
  1639.     hp->hlength = len;
  1640.     hp->hvalue = value;
  1641.     hp->hname = name;
  1642.     return hp->hvalue;
  1643. }
  1644.  
  1645. /* find the most recent hash node for name installed by install */
  1646. NODE *
  1647. lookup(name)
  1648. char *name;
  1649. {
  1650.     register NODE *bucket;
  1651.     register int len;
  1652.  
  1653.     len = strlen(name);
  1654.     bucket = variables[hash(name, len)];
  1655.     while (bucket) {
  1656.         if (bucket->hlength == len && STREQN(bucket->hname, name, len))
  1657.             return bucket->hvalue;
  1658.         bucket = bucket->hnext;
  1659.     }
  1660.     return NULL;
  1661. }
  1662.  
  1663. /*
  1664.  * Add new to the rightmost branch of LIST.  This uses n^2 time, so we make
  1665.  * a simple attempt at optimizing it.
  1666.  */
  1667. static NODE *
  1668. append_right(list, new)
  1669. NODE *list, *new;
  1670. {
  1671.     register NODE *oldlist;
  1672.     static NODE *savefront = NULL, *savetail = NULL;
  1673.  
  1674.     oldlist = list;
  1675.     if (savefront == oldlist) {
  1676.         savetail = savetail->rnode = new;
  1677.         return oldlist;
  1678.     } else
  1679.         savefront = oldlist;
  1680.     while (list->rnode != NULL)
  1681.         list = list->rnode;
  1682.     savetail = list->rnode = new;
  1683.     return oldlist;
  1684. }
  1685.  
  1686. /*
  1687.  * check if name is already installed;  if so, it had better have Null value,
  1688.  * in which case def is added as the value. Otherwise, install name with def
  1689.  * as value. 
  1690.  */
  1691. static void
  1692. func_install(params, def)
  1693. NODE *params;
  1694. NODE *def;
  1695. {
  1696.     NODE *r;
  1697.  
  1698.     pop_params(params->rnode);
  1699.     pop_var(params, 0);
  1700.     r = lookup(params->param);
  1701.     if (r != NULL) {
  1702.         fatal("function name `%s' previously defined", params->param);
  1703.     } else
  1704.         (void) install(params->param, node(params, Node_func, def));
  1705. }
  1706.  
  1707. static void
  1708. pop_var(np, freeit)
  1709. NODE *np;
  1710. int freeit;
  1711. {
  1712.     register NODE *bucket, **save;
  1713.     register int len;
  1714.     char *name;
  1715.  
  1716.     name = np->param;
  1717.     len = strlen(name);
  1718.     save = &(variables[hash(name, len)]);
  1719.     for (bucket = *save; bucket; bucket = bucket->hnext) {
  1720.         if (len == bucket->hlength && STREQN(bucket->hname, name, len)) {
  1721.             *save = bucket->hnext;
  1722.             freenode(bucket);
  1723.             if (freeit)
  1724.                 free(np->param);
  1725.             return;
  1726.         }
  1727.         save = &(bucket->hnext);
  1728.     }
  1729. }
  1730.  
  1731. static void
  1732. pop_params(params)
  1733. NODE *params;
  1734. {
  1735.     register NODE *np;
  1736.  
  1737.     for (np = params; np != NULL; np = np->rnode)
  1738.         pop_var(np, 1);
  1739. }
  1740.  
  1741. static NODE *
  1742. make_param(name)
  1743. char *name;
  1744. {
  1745.     NODE *r;
  1746.  
  1747.     getnode(r);
  1748.     r->type = Node_param_list;
  1749.     r->rnode = NULL;
  1750.     r->param = name;
  1751.     r->param_cnt = param_counter++;
  1752.     return (install(name, r));
  1753. }
  1754.  
  1755. /* Name points to a variable name.  Make sure its in the symbol table */
  1756. NODE *
  1757. variable(name, can_free)
  1758. char *name;
  1759. int can_free;
  1760. {
  1761.     register NODE *r;
  1762.     static int env_loaded = 0;
  1763.  
  1764.     if (!env_loaded && STREQ(name, "ENVIRON")) {
  1765.         load_environ();
  1766.         env_loaded = 1;
  1767.     }
  1768.     if ((r = lookup(name)) == NULL)
  1769.         r = install(name, node(Nnull_string, Node_var, (NODE *) NULL));
  1770.     else if (can_free)
  1771.         free(name);
  1772.     return r;
  1773. }
  1774.  
  1775. static NODE *
  1776. mk_rexp(exp)
  1777. NODE *exp;
  1778. {
  1779.     if (exp->type == Node_regex)
  1780.         return exp;
  1781.     else {
  1782.         NODE *n;
  1783.  
  1784.         getnode(n);
  1785.         n->type = Node_regex;
  1786.         n->re_exp = exp;
  1787.         n->re_text = NULL;
  1788.         n->re_reg = NULL;
  1789.         n->re_flags = 0;
  1790.         n->re_cnt = 1;
  1791.         return n;
  1792.     }
  1793. }
  1794.